<template>
  <div>
    <div class="mb-1">
      <a-checkbox v-model:checked="toggleExpand">展开/折叠</a-checkbox>
      <a-checkbox v-model:checked="toggleCheckAll">全选/全不选</a-checkbox>
    </div>
    <div class="border border-solid rounded-md border-gray-200 p-2">
      <a-skeleton active :loading="loading" :paragraph="{ rows: 5 }">
        <a-tree
          v-if="treeData && treeData.length > 0"
          v-model:expanded-keys="expandedKeys"
          :checked-keys="checkedKeys"
          checkable
          check-strictly
          :field-names="{ title: 'name', key: 'id' }"
          :tree-data="treeData"
          @check="handleCheck"
        />
      </a-skeleton>
    </div>
  </div>
</template>
<script lang="ts" setup>
import { onMounted, ref, watch, nextTick } from "vue";
import { findItemByKey, findParents, loopItem } from "/@/utils/treeData";
import { MenuItem, MenuType } from "/@/api/main/system/models";
import { getMenuList } from "/@/api/main/system";
import { TreeProps } from "ant-design-vue";

const props = defineProps<{
  value: number[] | null;
}>();

const emits = defineEmits(["change"]);

const toggleExpand = ref(false);
const toggleCheckAll = ref(false);
const checkedKeys = ref<{ checked: number[]; halfChecked: number[] }>({ checked: [], halfChecked: [] });
const expandedKeys = ref<number[]>([]);
const loading = ref(true);
const treeData = ref<MenuItem[]>([]);
onMounted(async () => {
  const data = await getMenuList();
  loading.value = false;
  if (data) {
    treeData.value = data;
  }
});

watch(toggleExpand, (v) => {
  if (v) {
    const keys: number[] = [];
    loopItem(treeData.value, (item) => {
      if (item.children && item.children.length > 0) {
        keys.push(item.id);
      }
    });
    expandedKeys.value = keys;
  } else {
    expandedKeys.value = [];
  }
});

watch(toggleCheckAll, (v) => {
  if (v) {
    const keys: number[] = [];
    loopItem(treeData.value, (item) => {
      keys.push(item.id);
    });
    checkedKeys.value = { checked: keys, halfChecked: [] };
  } else {
    checkedKeys.value = { checked: [], halfChecked: [] };
  }
});

watch(
  () => props.value,
  (newCheckedKeys) => {
    const checked: number[] = [];
    const halfChecked: number[] = [];
    if (newCheckedKeys) {
      newCheckedKeys.forEach((checkedKey) => {
        const re = findItemByKey(treeData.value, checkedKey);
        if (re) {
          let isAllChecked = true;
          let isAllUnchecked = false;
          loopItem(re.item.children || [], (item) => {
            if (newCheckedKeys.includes(item.id)) {
              isAllUnchecked = false;
            } else {
              isAllChecked = false;
            }
          });
          let isHalfChecked = !isAllChecked && !isAllUnchecked;
          if (isHalfChecked) {
            addKeyToArr(checkedKey, halfChecked);
          } else if (isAllChecked) {
            addKeyToArr(checkedKey, checked);
          }
        }
      });
    }
    checkedKeys.value = {
      checked,
      halfChecked,
    };
  }
);

const handleCheck: TreeProps["onCheck"] = (_: any, { node, checked }) => {
  const copyChecked = [...checkedKeys.value.checked];
  const copyHalfChecked = [...checkedKeys.value.halfChecked];
  //先处理自身以及自身所有子节点
  loopItem([node], (item) => {
    let index = copyChecked.indexOf(item.id);
    if (index === -1) {
      if (checked) {
        copyChecked.push(item.id);
      }
    } else {
      if (!checked) {
        copyChecked.splice(index, 1);
      }
    }
    index = copyHalfChecked.indexOf(item.id);
    if (index >= 0) {
      copyHalfChecked.splice(index, 1);
    }
  });
  const pIds: number[] = [];
  const pNodes: MenuItem[] = [];
  //找到所有祖先节点
  findParents(treeData.value, { keyValue: node.id }, pIds, pNodes);
  //处理每一个祖先节点 判断其是勾选还是反选还是半选
  pNodes.forEach((pNode) => {
    let isAllChecked = true;
    let isAllUnchecked = true;
    loopItem(pNode.children || [], (item) => {
      if (copyChecked.includes(item.id)) {
        isAllUnchecked = false;
      } else {
        isAllChecked = false;
      }
    });
    let isHalfChecked = !isAllChecked && !isAllUnchecked;
    if (isHalfChecked) {
      addKeyToArr(pNode.id, copyHalfChecked);
      removeKeyFromArr(pNode.id, copyChecked);
    } else {
      removeKeyFromArr(pNode.id, copyHalfChecked);
      if (isAllChecked) {
        addKeyToArr(pNode.id, copyChecked);
      } else {
        removeKeyFromArr(pNode.id, copyChecked);
      }
    }
  });
  checkedKeys.value = {
    checked: copyChecked,
    halfChecked: copyHalfChecked,
  };
  emits("change", copyChecked.concat(copyHalfChecked));
};

// function handleCheck(_: any, { node, checked }: { node: MenuItem; checked: boolean }) {

// }

function addKeyToArr(key: number, arr: number[]) {
  if (arr.indexOf(key) === -1) {
    arr.push(key);
  }
}

function removeKeyFromArr(key: number, arr: number[]) {
  const index = arr.indexOf(key);
  if (index >= 0) {
    arr.splice(index, 1);
  }
}
</script>
